package com.zzyk.microCloud.controller;

import com.zzyk.main.configuration.aspectj.annotation.OperaLog;
import com.zzyk.main.configuration.constant.CommonConstant;
import com.zzyk.main.configuration.exception.UserException;
import com.zzyk.main.configuration.jwt.JwtToken;
import com.zzyk.main.configuration.jwt.JwtUtil;
import com.zzyk.main.controller.BaseController;
import com.zzyk.main.model.pojo.SysUser;
import com.zzyk.main.model.vo.Message;
import com.zzyk.main.service.IMsgService;
import com.zzyk.main.service.ISysUserService;
import com.zzyk.main.utils.CaptchaUtils;
import com.zzyk.main.utils.MD5Utils;
import com.zzyk.main.utils.RedisUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping({"/sys"})
public class SysController extends BaseController {

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private IMsgService msgService;
    @Resource
    private RedisUtils redisUtils;

    /**
     * 登录的接口
     *
     * @param username 用户名
     * @param password 密码 不能直接和数据库的值做比较 需要运算 具体见shiro中我自定义的验证方法
     * @param captcha  验证码 经常因为session跨域取不到值 再取不到我就换WebSocket
     * @param session  获取验证码
     * @return 如果登陆成功会返回上次从哪来的URI(如果有)
     * @throws UserException 如果验证码不对或者登录异常则会
     * @throws IOException
     */
    @OperaLog("用户登录")
    @PostMapping("login")
    public Message login(@RequestParam("username") String username,
                         @RequestParam("password") String password,
                         @RequestParam("captcha") String captcha,
                         HttpSession session) throws UserException {
        String code = (String) session.getAttribute("code");
        // 从Session取验证码 先教研验证码对不对在检查账号对不对
        if (captcha == null || !captcha.equalsIgnoreCase(code)) {
            throw new UserException("验证码错误");
        }
        // 不管你验证码对不对 都不能用第二遍 删了再说
        Subject subject = SecurityUtils.getSubject();
//        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        SysUser sysUser = sysUserService.login(username);
        String sign = MD5Utils.sign(String.valueOf(password) + sysUser.getCreateTime().getTime() / 1000);
        if (sign.equalsIgnoreCase(sysUser.getPassword())) {
            String jwtToken = JwtUtil.sign(username, password);
            redisUtils.set(CommonConstant.PREFIX_USER_TOKEN + jwtToken, jwtToken);
            redisUtils.expire(CommonConstant.PREFIX_USER_TOKEN + jwtToken, JwtUtil.EXPIRE_TIME / 1000);
            Message message = Message.success();
            JwtToken jwtToken1 = new JwtToken(jwtToken);
            message.addData("token", jwtToken);
            subject.login(jwtToken1);
            return message;
        } else {
            throw new IncorrectCredentialsException();
        }
    }

    /**
     * 获取session中的验证码
     *
     * @param session
     * @return
     */
    @GetMapping("/getCaptcha")
    public String getCaptcha(HttpSession session) {
        return (String) session.getAttribute("code");
    }

    /**
     * 法院的登录接口
     *
     * @param username 用户名
     * @param password 密码 不能直接和数据库的值做比较 需要运算 具体见shiro中我自定义的验证方法
     * @return 如果登陆成功会返回上次从哪来的URI(如果有)
     * @throws UserException 如果验证码不对或者登录异常则会
     * @throws IOException
     */
    @OperaLog("法院的登录接口")
    @GetMapping("BankLogin")
    public void login(@RequestParam("username") String username,
                      @RequestParam("password") String password,
                      ServletResponse response,
                      HttpSession session) throws IOException {
        // 从Session取验证码 先教研验证码对不对在检查账号对不对
        Subject subject = SecurityUtils.getSubject();
//        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//        subject.login(token);
//
//        if (subject.isAuthenticated()) {
//            SysUser user = (SysUser) subject.getPrincipal();
//            session.setAttribute("username", user.getDisplayName());
//            // 这块是想弄从哪跳过来的还跳回哪去 给前台传了个上次访问的URL
//            PrintWriter out = response.getWriter();
//            out.println("<script language='javascript'>window.location.href='/pages/home.html';</script>");
//            out.close();
//        } else {
//            throw new IncorrectCredentialsException();
//        }
        SysUser sysUser = sysUserService.login(username);
        String sign = MD5Utils.sign(String.valueOf(password) + sysUser.getCreateTime().getTime() / 1000);
        if (sign.equalsIgnoreCase(sysUser.getPassword())) {
            String jwtToken = JwtUtil.sign(username, password);
            redisUtils.set(CommonConstant.PREFIX_USER_TOKEN + jwtToken, jwtToken);
            redisUtils.expire(CommonConstant.PREFIX_USER_TOKEN + jwtToken, JwtUtil.EXPIRE_TIME / 1000);
            Message message = Message.success();
            JwtToken jwtToken1 = new JwtToken(jwtToken);
            message.addData("token", jwtToken);
            subject.login(jwtToken1);
//            return message;
            PrintWriter out = response.getWriter();
            out.println("<script language='javascript'>window.location.href='/pages/home?token=" + jwtToken + "';</script>");
            out.close();
        } else {
            throw new IncorrectCredentialsException();
        }
    }

    /**
     * 获取验证码的方法 说实话这块很难受 不优雅
     *
     * @param response 返回验证码的时候是媒体流的方式返回的
     * @param session  需要把验证码放到Session里面 他登录的时候提交回来 http是无状态的很烦啊
     *                 再遇到跨域取不到session我就用WebSocket了
     */
    @RequestMapping("captcha")
    public void captcha(HttpServletResponse response, HttpSession session) throws UserException {
        Message message = CaptchaUtils.generate(100, 38, 4);
        response.setContentType("image/png");
        session.removeAttribute("code");
        session.setAttribute("code", message.getData("code"));
        byte[] data = (byte[]) message.getData("img");
        try (OutputStream out = response.getOutputStream()) {
            out.write(data);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @RequestMapping("userInfo")
    public Message status() throws UserException {
        SysUser sysUser = currentUser();
        sysUser.setPassword(null);
        return Message.success().addData("data", sysUserService.getUserWithRole(sysUser.getId()));
    }

    @OperaLog("修改密码")
    @PostMapping("changePassword")
    @Transactional
    public Message changePassword(@RequestParam("oldPassword") String oldPassword,
                                  @RequestParam("newPassword") String newPassword) throws UserException {
        SysUser sysUser = currentUser();
        sysUserService.checkPassword(sysUser.getUsername(), oldPassword);
        sysUser.setPassword(newPassword);
        sysUserService.updateUser(sysUser);
        logout();
        return Message.success("密码修改成功");
    }

    @RequestMapping("changePhone")
    public Message changePhone(@RequestParam("username") String username,
                               @RequestParam("captcha") String captcha) throws UserException {
        String code = msgService.get(username);
        if (code == null || !code.equalsIgnoreCase(captcha)) {
            throw new UserException("验证码错误");
        }
        SysUser sysUser = currentUser();
        sysUser.setUsername(username);
        if (sysUserService.updateUser(sysUser) > 0) {
            logout();
            return Message.success("手机号修改成功,请重新登录");
        } else {
            return Message.failed();
        }
    }

    @PostMapping("forgetPassword")
    public Message forgetPassword(@RequestParam("username") String username,
                                  @RequestParam("captcha") String captcha,
                                  @RequestParam("password") String password) throws UserException {
        String code = msgService.get(username);
        if (code == null || !code.equalsIgnoreCase(captcha)) {
            throw new UserException("验证码错误");
        }
        SysUser sysUser = sysUserService.getUser(username);
        if (sysUser == null) {
            throw new UserException("用户不存在");
        }
        sysUser.setPassword(password);
        return Message.success().addData("data", sysUserService.updateUser(sysUser));
    }

    @RequestMapping("exist")
    public Map existPhone(@RequestParam("username") String username,
                          @RequestParam(value = "type", defaultValue = "true") Boolean type) {
        Map<String, Boolean> result = new HashMap<>();
        if (sysUserService.getUser(username) == null) {
            result.put("valid", type);
        } else {
            result.put("valid", !type);
        }
        return result;
    }

    @PostMapping("register")
    public Message register(SysUser sysUser,
                            @RequestParam("captcha") String captcha) throws UserException {
        String code = msgService.get(sysUser.getUsername());
        if (code == null || !code.equalsIgnoreCase(captcha)) {
            throw new UserException("验证码错误");
        }
        if (sysUserService.getUser(sysUser.getUsername()) != null) {
            throw new UserException("用户已存在");
        }
        sysUser.setStatus(0);
        return Message.success().addData("data", sysUserService.addUser(sysUser));
    }

    @RequestMapping("sendMsg")
    public Message message(@RequestParam("username") String username) throws UserException {
        msgService.send(username);
        return Message.success().addData("data", "验证码发送成功");
    }

    @RequestMapping("logout")
    public Message message(HttpServletRequest request, HttpServletResponse response) {
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            cookie.setMaxAge(0);
            cookie.setPath("/");
            response.addCookie(cookie);
        }
        HttpServletRequest httpServletRequest = request;
        String token = httpServletRequest.getHeader(CommonConstant.ACCESS_TOKEN);
        redisUtils.del(CommonConstant.PREFIX_USER_TOKEN + token);
        try {
            logout();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Message.success("您已安全退出");
    }

}
